package vg.modules.opener;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileFilter;

import vg.services.data_base_manager.data.header.GraphModelHeader;
import vg.services.main_manager.MainManager;
import vg.services.plugin_manager.event_and_request.event.UIEventOpenNewGraph;
import vg.services.plugin_manager.event_and_request.request.AUIRequest;
import vg.services.plugin_manager.event_and_request.request.UIRequestLoadProject;
import vg.services.plugin_manager.event_and_request.request.UIRequestSaveProject;
import vg.services.plugin_manager.interfaces.IPlugin;
import vg.services.plugin_manager.realization.PluginParameter;
import vg.services.user_interface_manager.interfaces.UserInterfaceObserverAdapter;

public class GUIOpener implements IPlugin {
	// Main data
    private PluginParameter pluginParameter;

	// Swing components
    private JFileChooser fileChooser;

	// Defines
	private final static String DEF_LAST_OPEN_GRAPH_DIR = "GRAPH_OPENER_LastDir";
	/**
	 * Installer.
	 */
	public void install(final PluginParameter pluginParameter) {
		this.pluginParameter = pluginParameter;

        final JMenuItem jMenuItem = new JMenuItem("Open file");
		jMenuItem.setIcon(new ImageIcon("./data/resources/textures/openFile.png"));
		//---------------------------------------
		jMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openGraph();
			}
		});
		jMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		//---------------------------------------
        pluginParameter.userInterfaceManager.addMenuItem(jMenuItem, "file");
        pluginParameter.userInterfaceManager.addObserver(new UserInterfaceObserverAdapter() {
            @Override
            public void dispatchRequest(AUIRequest request) {
                switch(request.getType()) {
                    case DEF_SAVE_PROJECT: {
                        UIRequestSaveProject buf = (UIRequestSaveProject)request;
                        saveProject(buf.getPath());
                        break;
                    }

                    case DEF_LOAD_PROJECT: {
                        final UIRequestLoadProject buf = (UIRequestLoadProject)request;
                        MainManager.threadPool.submit(new Runnable() {
                            public void run() {
                                loadProject(buf.getPath());
                            }
                        });
                        break;
                    }

                    default: break;
                }
            }
        });

        fileChooser = new JFileChooser(".");

        for (final String ext : ConsoleOpener.getAvailableExtensions()) {
        	fileChooser.addChoosableFileFilter(new FileFilter() {
				@Override
                public String getDescription() {
					return ext + " file (*." + ext +")";
				}

                @Override
                public boolean accept(File f) {
					return f != null && (f.isDirectory() || f.getName().toLowerCase().endsWith(ext));
				}
			});
        }
	}
	private void openGraph() {
        // set last directory for file chooser
        String lastDir = MainManager.config.getProperty(GUIOpener.DEF_LAST_OPEN_GRAPH_DIR);
        if(lastDir != null) {
            fileChooser.setCurrentDirectory(new File(lastDir));
        }

        // update file chooser interface
        fileChooser.updateUI();

        // show it
		if (fileChooser.showOpenDialog(pluginParameter.userInterfaceManager.getMainFrame()) == JFileChooser.APPROVE_OPTION) {
			MainManager.logger.printDebug("[" + this.getClass().getName() + ".openGraph] [PROCESS] Open file = " + fileChooser.getSelectedFile().getPath());
			MainManager.config.setProperty(GUIOpener.DEF_LAST_OPEN_GRAPH_DIR, fileChooser.getCurrentDirectory().getAbsolutePath());
			MainManager.threadPool.submit(new Runnable() {
				public void run() {
					try {
						String fileName = fileChooser.getSelectedFile().getPath();
						List<Integer> new_graph_id = ConsoleOpener.openFile(fileName, pluginParameter.graphDataBase);
						MainManager.logger.printDebug("[" + this.getClass().getName() + ".openGraph] [OK] Open file = " + fileChooser.getSelectedFile().getPath());
						if(new_graph_id == null || new_graph_id.isEmpty()) {
							MainManager.windowMessage.errorMessage("Can't open file. May be file is empty", "Error");														
						} else {
							for(Integer buf : new_graph_id) {
								GraphModelHeader gh = pluginParameter.graphDataBase.getGraphModelHeader(buf);
								if(gh != null) {
									UIEventOpenNewGraph ong = new UIEventOpenNewGraph(buf, gh.name);
                                    pluginParameter.userInterfaceManager.sendEvent(ong);
								} else {
									MainManager.windowMessage.errorMessage("Can't open file. Database error", "Error");
								}							
							}
						}
					} catch (Throwable e) {
						MainManager.logger.printException(e);
						MainManager.windowMessage.showExceptionMessage(new Exception("Can't open file.\nException : " + e.getMessage()));
					}
				}
			});
		}
	}

	/**
	 * This method saves all files, which contain 
	 * graphs and were used by user.
	 */
	private void saveProject(String path) {
		ArrayList<String> dontSavedFiles = new ArrayList<String>();	
		for (String fileName : ConsoleOpener.getOpenedFilesList()) {
			try {
				File oldFile = new File(fileName);
				File newFile = new File(path + File.separator + oldFile.getName());
				//we don't want have problems with coping file into itself
				if (oldFile.compareTo(newFile) == 0) {
					continue;
				}
				FileChannel originalGraphFile = new FileInputStream(oldFile).getChannel();
				FileChannel copyFile = new FileOutputStream(newFile).getChannel();
				try {
					originalGraphFile.transferTo(0, originalGraphFile.size(), copyFile);
				} catch (IOException e1) {
                    MainManager.logger.printException(e1);
				} finally {
					if (originalGraphFile != null) 
						originalGraphFile.close();
					if (copyFile != null)
						copyFile.close();
				}
			} catch (IOException e1) {
				MainManager.logger.printException(e1);
				dontSavedFiles.add(fileName);
			}						
		}

        // show warning
		if (!dontSavedFiles.isEmpty()) {
			StringBuilder warningMessage = new StringBuilder("Could not save these files:");
			for (String it : dontSavedFiles) {
				warningMessage.append("\n");
				warningMessage.append(it);
			}
			
			MainManager.windowMessage.warningMessage(warningMessage.toString(), "Save project");
		}
	}

	/**
	 * This method loads all files, which contain 
	 * graphs and were used by user.
	 */
	private void loadProject(String path) {
		File dir = new File(path);
		if(dir.exists() && dir.isDirectory()) {		
			ArrayList<String> dontOpenedFiles = new ArrayList<String>();	
			for (String fileName : dir.list()) {
				String filePath = dir.getPath() + File.separator + fileName;
				for (final String ext : ConsoleOpener.getAvailableExtensions())
					if (filePath.toLowerCase().endsWith(ext)) {
						// TODO Need save to vgdb file and read from it.
/*						try {						
							int newGraphId = ConsoleOpener.openFile(filePath, this.parameter.model);
							GraphHeader gh = parameter.model.getGraphHeader(newGraphId);
							if(gh != null) {
								UIEventOpenNewGraph ong = new UIEventOpenNewGraph(newGraphId, gh.name);
								parameter.userInterfaceManager.addEvent(ong);
							} else {
								VisualGraph.windowMessage.errorMessage("Can't open file. Database error.", "Error");							
							}							
						} catch (CoreException e) {
							VisualGraph.logger.printException(e);
							dontOpenedFiles.add(filePath);						
						}
*/					}
			}
			if (!dontOpenedFiles.isEmpty()) {
				StringBuilder warningMessage = new StringBuilder("Could not open file\n");
				for (String doesntOpenedFile : dontOpenedFiles) {
					warningMessage.append("\n");
					warningMessage.append(doesntOpenedFile);
				}
				MainManager.windowMessage.warningMessage(warningMessage.toString(), "Open project");
			}
		} else {
			MainManager.logger.printError("[" + this.getClass().getName() + ".loadProject] is not directory (or not exist)");
		}
	}
}
